package org.langqiao.appproject.俄罗斯方块;
import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.applet.Applet;
import java.applet.AudioClip;
import javax.swing.*;
import java.io.*; 
class Tetris extends JFrame{ //implements ActionListener,MouseListener {
	//public JRadioButton radio1,radio2,radio3,radio4,radio5;//这五个单选按钮分别是“开始游戏”、“提高级数”、“降低级数”、“停止游戏”、“结束游戏”
	//public JLabel label1,label2;//定义两个标签，分别代表“分数”和“级别”
	public static JTextField levelField,scoreField;//定义两个文本编辑行，分别显示“分数”、“级别”
    public static int level=1,score=0;
	public  static boolean isPlay=false;
	//public  Color color;//各个面板块的颜色
	public  static MyTimer timer;//定时器
	GameCanvas gameScr;//画布，播放声音
	Music musiceg;//播放音乐的变量
//***************************************构造方法，对窗口界面进行设置	
    Tetris()//构造方法
	{
		super("俄罗斯方块V1.0制作，制作人：杨明洋");//窗口的框架的名字
	    //Dimension dim=getToolkit().getScreenSize();//获得屏幕尺寸大小
	    this.setBounds(400,200,600,480);//设置窗口的位置和大小
	    this.setLayout(new GridLayout(1,2));//设置窗口布局，1行2列
	    
	  //关闭窗口
	    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    //levelField.addMouseListener(this);//文本行1注册单击鼠标事件监听器
	    //scoreField.addMouseListener(this);//文本行2注册单击鼠标事件监听器
	    //this.addmyMenu();//调用自定义方法，添加菜单
	    //this.setVisible(true);//设置窗口可见
	//}
	//public void addmyMenu();//添加菜单项，对话框
	//{
		JMenuBar menubar=new JMenuBar();//菜单栏
		this.setJMenuBar(menubar);//窗口框架上添加菜单栏
		String menustr[]={"文件","帮助","音乐"};//菜单栏上的菜单项
		JMenu menu[]=new JMenu[menustr.length];
		for(int i=0;i<menustr.length;i++)
		{
			menu[i]=new JMenu(menustr[i]);
			menubar.add(menu[i]);//菜单栏中加入菜单
		}
		JMenuItem youxi1=new JMenuItem("开始 游戏");
		JMenuItem youxi2=new JMenuItem("退出游戏");
		menu[0].add(youxi1);
		menu[0].add(youxi2);
		//menu[0].add(new JMenu("开始游戏"));//生成菜单项"开始游戏"加入到菜单
		//menu[0].addSeparator();//在两个生成 的菜单项之间加一个分隔符
		//menu[0].add(new JMenu("结束游戏"));//生成的菜单项“结束游戏”加入到菜单”文件“
		youxi2.addActionListener(new ActionListener(){//匿名类写法，退出程序
			public void actionPerformed(ActionEvent e)
			{
				System.exit(1);
			}
		});
		//****************************打开帮助文档
		JMenuItem my=new JMenuItem("游戏介绍");
		menu[1].add(my);//生成的菜单项“游戏介绍”加入到菜单”帮助“
		my.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				try{
					Runtime rt=Runtime.getRuntime();
					rt.exec("notepad.exe help.txt");//打开记事本程序
				}
				catch(Exception e1)
				{
					e1.printStackTrace();
				}
			}
		});
		JMenuItem music1=new JMenuItem("播放音乐");
		JMenuItem music2=new JMenuItem("关闭音乐");
		//menu[2].add(new JMenu("播放音乐"));//生成的菜单项“播放音乐“加入到菜单”音乐“
		//menu[2].add(new JMenu("关闭音乐"));//生成的菜单项"关闭音乐"加入到菜单”音乐”
		menu[2].add(music1);
		menu[2].add(music2);
		musiceg=new Music();
		//**************************播放音乐
		music1.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				musiceg.loop();
			}
		});
		//***************************关闭音乐
		music2.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				musiceg.stop();
			}
		});
		gameScr=new GameCanvas();
		this.add(gameScr);
		//注册键盘监听事件
		gameScr.addKeyListener(gameScr);
		timer=new MyTimer(gameScr);
		timer.setDaemon(true);//将该线程标记为守护线程或用户线程
		timer.start();//线程开始
		timer.suspend();//线程守护
		youxi1.addActionListener(new Command(Command.button_play,gameScr));
		//*****************************************************************窗口面板左侧的设置完毕
		//*****************************************************************窗口面板右侧的设置开始
		JPanel rightScr=new JPanel();
		rightScr.setLayout(new GridLayout(2,1,0,0));//设置右侧面板的布局，为两行1列指定组件间的水平和垂直间距都为0
		rightScr.setBackground(Color.white);//设置背景颜色
		this.add(rightScr);
		
		MyPanel inforScr=new MyPanel();
		inforScr.setLayout(new GridLayout(4,1,0,5));//设置右侧面板上半部分信息面板的布局
		inforScr.setBackground(Color.green);//设置该画布的颜色为绿色
		rightScr.add(inforScr);//在rightCanvas面板上增加intforCanvas面板
		//****************************设置右侧面板上的标签
		JLabel score1=new JLabel("分数:",JLabel.LEFT);//定义一个“级数”标签
		JLabel levell=new JLabel("级数:",JLabel.LEFT);//定义一个“分数”标签
		levelField=new JTextField();
	    scoreField=new JTextField();
	    levelField.setEditable(false);//不可编辑
		scoreField.setEditable(false);//不可编辑
		inforScr.add(score1);//在面板上增加“分数”这个标签
		inforScr.add(scoreField);
		inforScr.add(levell);//在面板上增加“级数”这个标签
		inforScr.add(levelField);
		
	    
		
//		inforCanvas.add(levelField);//在面板上增加“级数”这个文本行
//		inforCanvas.add(scoreField);//在面板上增加“分数”这个文本行
		//设置初值
		levelField.setText("1");
		scoreField.setText("0");
		//对右侧窗口下半部分进行设置
		MyPanel controlScr=new MyPanel();//实例化一个contrilCanvas面板对象
		controlScr.setLayout(new GridLayout(5,1,0,5));//设置布局存放5个按钮
		controlScr.setBackground(Color.red);//设置背景色
		rightScr.add(controlScr);//是在右侧面板上添加控制按钮的画布
		//定义开始游戏按钮
		JButton play_b=new JButton("开始游戏");
		play_b.addActionListener(new Command(Command.button_play,gameScr));
		//定义增加级数按钮
		JButton level_up_b=new JButton("增加级数");
		level_up_b.addActionListener(new Command(Command.button_levelup,gameScr));
		//定义降低级数按钮
		JButton level_down_b=new JButton("降低级数");
		level_down_b.addActionListener(new Command(Command.button_leveldown,gameScr));
		//定义暂停游戏按钮
		JButton pause_b=new JButton("暂停游戏");
		pause_b.addActionListener(new Command(Command.button_pause,gameScr));
		//定义退出游戏按钮
		JButton exit_b=new JButton("退出游戏");
		exit_b.addActionListener(new Command(Command.button_exit,gameScr));
		//在controlCanvas面板上添加下面5个按钮
		controlScr.add(play_b);
		controlScr.add(level_up_b);
		controlScr.add(level_down_b);
		controlScr.add(pause_b);
		controlScr.add(exit_b);
		
		this.setResizable(false);//窗口大小不可变
		this.setVisible(true);//设置窗口可见
		gameScr.requestFocus();//请求此控件获得输入焦点，并且此控件的顶层祖先获得焦点的window
	}
}
	//******************************构造函数结束
	//******************************重写MyPanel类，使JPanel类内陷，即周围留有空间
	class MyPanel extends JPanel
	{
		private static final long serialVersionUID=1L;//在反序列化中，确保类版本的兼容性，可以用private static  final long serialVersionUID这个属性
		public Insets getInsets()
		{
			return new Insets(30,100,30,100);//返回窗口右下角阴影部分按钮，参数分别是top、left、bottom、right
		}
		
	}
	//********************************游戏画布类
	class GameCanvas extends Canvas implements KeyListener
	{
		private static final long serialVersionUID=1L;
		int rowNum;//正方格的行数
		int columnNum;//正方格的列数
		final int unitSize=30;//正方格边长的大小
		int blockInitRow;//新方块初始化的位置的横坐标
		int blockInitCol;//新方块初始化的位置的纵坐标
		int maxAllowRowNum;//有多少未肖
	    int [][] scrArr;//定义一个左侧的画布数组
	    Block b;
	    GameCanvas()//构造方法
	    {
	    	scrArr=new int[32][32];
	    	rowNum=15;
	    	columnNum=10;
	    	blockInitRow=rowNum-1;
	    	blockInitCol=columnNum/2-2;
	    	maxAllowRowNum=rowNum-2;
	    	b=new Block(this);
	    }
	    public int getInitRow()//返回新块行坐标的方法
	    {
	    	return(blockInitRow);
	    }
	    public int getInitCol()//返回新块的列坐标的方法
	    {
	    	return(blockInitCol);
	    }
	    //返回屏幕中（row,column）的坐标值
	    public int getScrArrXY(int row,int col)
	    {
	    	if(row<0||row>=rowNum||col<0||col>=columnNum)
	    		return(-1);
	    	else
	    		return(scrArr[row][col]);
	    }
	    //判断游戏是否结束
	    boolean isGameEnd() 
	    {
	    	for(int col=0;col<columnNum;col++)
	    	{
	    		if(scrArr[maxAllowRowNum][col]!=0)
	    			return true;
	    	}
	    	return false;
	    	
	    }
		//开始游戏，在画布上画方块将屏幕数组清零的方法
	    void initScr()
	    {
	    	for(int i=0;i<rowNum;i++)
	    		for(int j=0;j<columnNum;j++)
	    			scrArr[i][j]=0;
	    	b.reset();
	    	repaint();
	    			
	    }
	    //程序运行时，桌布背景为黑色
	    public void paint(Graphics g)
	    {
	    	for(int i=0;i<rowNum;i++)
	    		for(int j=0;j<columnNum;j++)//这里由于不小心，j++写成了i++,造成点击开始游戏后，游戏区仅仅只是左侧一小片是黑色，其余是白色
	    			drawUnit(i,j,scrArr[i][j]);
	    }
	    public void drawUnit(int row,int col,int type )
	    {
	    	scrArr[row][col]=type;
	    	Graphics g=getGraphics();
	    	switch(type){
	    	case 0:g.setColor(Color.black);//以背景颜色画
	    	break;
	    	case 1:g.setColor(Color.cyan);//蓝绿色
	    	break;//画正在下落的方块
	    	case 2:g.setColor(Color.magenta);//洋红色
	    	break;//画已经落下的方块 	
        	}
	    	g.fill3DRect(col*unitSize,getSize().height-(row+1)*unitSize,unitSize,unitSize,true);
	    	g.dispose();//处理图形上下文并释放它所使用的系统的所有资源
	    	
	    	
	    }
		public Block getBlock()
		{
			return b;
		}
		public void  keyTyped(KeyEvent e){}
		public void keyReleased(KeyEvent e){}
		//处理键盘处理方法
		public void keyPressed(KeyEvent e)
		{
			if(!Tetris.isPlay)
				return;
			switch(e.getKeyCode())
			{
			case KeyEvent.VK_DOWN:
				b.fallDown();
				break;
			case KeyEvent.VK_LEFT:
				b.leftMove();
				break;
			case KeyEvent.VK_RIGHT:
			    b.rightMove();
			    break;
			case KeyEvent.VK_UP:
				b.leftTurn();
				break;
			}
			
		}
		//消除满行
		public void  deletefullline()
		{
			int full_line=0;//定义满行的个数
			int k=0;
			for(int i=0;i<rowNum;i++)
			{
				boolean isfull=true;
			    L1:for(int j=0;j<columnNum;j++)
				if(scrArr[i][j]==0)
				{
					k++;
					isfull=false;
				    break L1;
			    }
			    if(isfull)
				full_line++;
			    if(k!=0 &&k-1!=i &&!isfull)
			    for(int j=0;j<columnNum;j++)
			    {
				  if(scrArr[i][j]==0)
					  drawUnit(k-1,j,0);
				  else
					  drawUnit(k-1,j,2);
			     scrArr[k-1][j]=scrArr[i][j];
			    }
			
			}
			for(int i=k-1;i<rowNum;i++)
			{
				for(int j=0;j<columnNum;j++)
				{
					drawUnit(i,j,0);
					scrArr[i][j]=0;
				}
			}
			Tetris.score=Tetris.score+full_line*5;
			Tetris.scoreField.setText(""+Tetris.score);
		}
		
	}
	class Command implements ActionListener
	{
		static final int button_play=1;//给按钮分配编号
		static final int button_levelup=2;
		static final int button_leveldown=3;
		static final int button_exit=4;
		static final int button_pause=5;
	    static boolean pause_resume=true;//控制游戏暂停，初值表示游戏正在运行
	    int curButton;//当前按钮
	    GameCanvas scr;
	    //控制按钮类的构造方法
	    Command(int button,GameCanvas scr)
	    {
	    	curButton=button;
	    	this.scr=scr;
	    }
	    public void actionPerformed(ActionEvent e)
	    {
	    	switch(curButton)
	    	{
	    	     //开始游戏
	    	    case button_play:
	    	    	if(!Tetris.isPlay)//游戏没有开始时，按开始游戏按钮有效，游戏开始后，按开始游戏按钮无效，画布上出现方块
	    	    	{
	    	    		scr.initScr();
	    	    		Tetris.isPlay=true;
	    	    		Tetris.score=0;
	    	    		Tetris.scoreField.setText("0");
	    	    		Tetris.timer.resume();//解除当前进程的挂起在状态
	    	    	}
	    	    	scr.requestFocus();
	    	    	break;
	    	    		
	    	    //增加等级	
	    	    case button_levelup:
	    	    	if(Tetris.level<10)
	    	    	{
	    	    		Tetris.level++;
	    	    	Tetris.levelField.setText(""+Tetris.level);
	    	    	Tetris.score=0;
	    	    	Tetris.scoreField.setText(""+Tetris.score);
	    	    	//Tetris.levelField;
	    	    	}
	    	    	scr.requestFocus();
	    	    	break;
	    	    //降低等级
	    	    case button_leveldown:
	    	    	if(Tetris.level>1)
	    	    	{
	    	    		Tetris.level--;
	    	    		Tetris.levelField.setText(""+Tetris.level);
	    	    		Tetris.score=0;
	    	    		Tetris.scoreField.setText(""+Tetris.score);
	    	    	}
	    	    	scr.requestFocus();
	    	    	break;
	    	    //暂停游戏
	    	    case button_pause:
	    	    	if(pause_resume)
	    	    	{
	    	    		Tetris.timer.suspend();//将该线程挂起
	    	    	    pause_resume=false;
	    	        }
	    	    	else
	    	    	{
	    	    		Tetris.timer.resume();
	    	    		pause_resume=true;
	    	    	}
	    	    	scr.requestFocus();
	    	    	break;
	    	    //退出游戏
	    	    case button_exit:
	    	    	System.exit(0);
	    	}
	    }
	}
	//关于方块的初始化操作
	class Block//方块类
	{
		//俄罗斯方块的数据结构
		static int[][] pattern={
		       {0x0f00,0x4444,0x0f00,0x4444},//本行表示长条的四种状态 
		       {0x04e0,0x0464,0x00e4,0x04c4}, 
		       {0x4620,0x6c00,0x4620,0x6c00}, 
		       {0x2640,0xc600,0x2640,0xc600},
		       {0x6220,0x1700,0x2230,0x0740}, 
		       {0x6440,0x0e20,0x44c0,0x8e00}, 
		       {0x0660,0x0660,0x0660,0x0660}
		};//十六进制表示模块的集中状态，
		int blockType;//块的模式号0~6
		int turnState;//块翻转的状态0~3
		int blockState;//块的下落状态
		int row,col;//行，列
		GameCanvas scr;
		//方块类 构造函数
		Block(GameCanvas temp)
		{
			this.scr=temp;
			blockType=(int)(Math.random()*1000)%7;//产生0~1000的随级数，最后与7做取模运算，范围为0~6
			turnState=(int)(Math.random()*1000)%4;//范围为0~3
			blockState=1;
			row=scr.getInitRow();
			col=scr.getInitCol();
			//dispBlock(1);//显示下落的块
		}
		//重新初始化，并显示新落下的块
		public void reset()
		{
			blockType=(int)(Math.random()*1000)%7;
			turnState=(int)(Math.random()*1000)%4;
			blockState=1;
			row=scr.getInitRow();
			col=scr.getInitCol();
			dispBlock(1);//显示落下的块
		}
		//实现块落下的操作
		public boolean fallDown()//返回值是布尔型的
		{
			if(blockState==2)
				return(false);
			if(assertValid(blockType,turnState,row-1,col))
			{
				dispBlock(0);
				row--;
				dispBlock(1);
				return(true);
			}
			else
			{
				blockState=2;
				dispBlock(2);
				return(false);
			}
		}
		//实现块向左移动的操作
		public void leftMove()
		{
			if(assertValid(blockType,turnState,row,col-1))
			{
				dispBlock(0);
				col--;
				dispBlock(1);
				
			}
		}
		//实现块向右移动的操作
		public void rightMove()
		{
			if(assertValid(blockType,turnState,row,col+1))
			{
				dispBlock(0);
				col++;
				dispBlock(1);
				
			}
		}
		//实现翻转的操作
		public void leftTurn()
		{
			if(assertValid(blockType,(turnState+1)%4,row,col))
			{
			    dispBlock(0);
			    turnState=(turnState+1)%4;
			    dispBlock(1);
			  
			}
		}
		//判断是否正确的方法
		boolean assertValid(int t,int s,int row,int col)
		{
			int k=0x8000;
			for(int i=0;i<4;i++)
			{
				for(int j=0;j<4;j++)
				{
					if((int)(pattern[t][s]&k)!=0)
					{
						int temp=scr.getScrArrXY(row-i,col+j);
						if(temp<0||temp==2)
							return false;
					}
					k=k>>1;
				}
				
			}
			return true;
		}
	    //画形状的 方法
		public synchronized void dispBlock(int s)//同步方法,使用synchronized声明一个方法，该方法称为同步方法
		{
			int k=0x8000;
			for(int i=0;i<4;i++)
			{
				for(int j=0;j<4;j++)
				{
					if(((int)pattern[blockType][turnState]&k)!=0)
					{
						scr.drawUnit(row-i,col+j,s);
					}
					k=k>>1;
				}
			
			}
		}//dispBlock()方法结束
	}
		//设置定时器		
	class MyTimer extends Thread
	{
	    	GameCanvas scr;
	    	public MyTimer(GameCanvas scr)//构造方法
	    	{
	    		this.scr=scr;
	    	}
	    	//运行游戏，控制速度
	    	public  void run()//必须为公有函数
	    	{
	    		while(true)
	    		{
	    			try
	    			{
	    				this.sleep((10-Tetris.level+1)*100);
	    			}
	    			catch(InterruptedException e){}
	    			if(!scr.getBlock().fallDown())
	    			{
	    				scr.deletefullline();
	    				if(scr.isGameEnd())
	    				{
	    					Tetris.isPlay=false;
	    					this.suspend();//进程挂起
	    				}
	    				else
	    				
	    					scr.getBlock().reset();
	    				
	    					
	    			}
	    		}
	    	}
	}
//	关闭窗口
	/*class MyWindowListener extends WindowAdapter
	{
		public void windowClosing(WindowEvent e)
		{
			System.exit(0);
		}
	}*/
	class Music
	{
		AudioClip sound;
		public Music()
		{
			File soundFile=new File("super.mid");
			try
			{
				URL ul=soundFile.toURL();
				sound=Applet.newAudioClip(ul);
			}
			catch(MalformedURLException e){}
		}
		public void loop()
		{
			sound.loop();//循环播放音乐
		}
		public void stop()
		{
			sound.stop();//停止播放音乐
		}
	}

	//***********************************主函数
public class MyTetris
{
	public static void main(String[] args)
	{
	   Tetris Russia_Block=new Tetris();
//	   关闭窗口的
//	   MyWindowListener win_Listener=new MyWindowListener();
//	   Russia_Block.addWindowListener(win_Listener);
    }
}
	


